<?php
/**
 * Simpel utility around the oggz-info program provided by the ogg-utils
 * Extracts the most basic and elementary information about the video file.
 *
 * @author		Matthijs van Henten <matthijs@waag.org>
 * @license		Gnu GPL http://www.gnu.org/licenses/gpl.html
 */
class Ogg_Info{
	// path to look for oggz-info: override by declaring OGGZ_SEARCH_PATH globally
	const OGGZ_SEARCH_PATH =
	'/bin;/usr/bin;/usr/local/bin;/opt/bin/;/opt/local/bin';

	private $_duration;
	private $_contentDuration;
	private $_videoFramerate;
	private $_videoWidth;
	private $_videoHeight;
	private $_audioSamplerate;
	private $_audioChannels;

	private $path;

	/**
	 * class constructor.
	 * initialize with a path to the file you want to inspect
	 */
	public function __construct( $path ){
		$this->path = $path;
	}

	/**
	 * Provide acces to the class values and tries to fetch them
	 * if they're not set
	 *
	 * @param string $name
	 * @return mixed $value or null
	 */
	public function __get( $name ){
		$property = sprintf( '_%s', $name );

		if( property_exists( $this, $property ) ){
			if( null == $this->$property ){
				$this->getInfo();
			}

			return $this->$property;
		}
	}

	/**
	 * Set values. Parses name to convert Things-With_Dashes into _className
	 *
	 * @param string $name Name of the property
	 * @param mixed $value Value for the property
	 */
	public function __set( $name, $value ){
		if( empty( $name ) ) return; // seems there's some trash coming in.
		$name 		= join( '', array_map( 'ucfirst', explode( '|', str_replace( array('_','-'), '|', $name ) ) ) );
		$name{0} 	= strtolower( $name{0} );

		$property = sprintf('_%s', $name );

		if( property_exists( $this, $property ) ){
			if( ( $method = sprintf( 'set%s', ucfirst( $name ) ) ) && method_exists( $this, $method ) ){
				return call_user_func( array( $this, $method ), $value );
			}
			else{
				$this->$property = $value;
			}
		}
	}

	/**
	 * Get info about the movie.
	 * Executes oggz-info and passes the result to __set
	 *
	 * @return void
	 */
	private function getInfo(){
		if( null !== $this->path && file_exists( $this->path ) ){
			$cmd = $this->getPath( 'oggz-info' );
			$lines = array();

			exec( sprintf( '%s "%s"', $cmd, escapeshellcmd($this->path)), $lines );

			foreach( $lines as $line ){
				// part after the : contains the informatino. trim it and __set it.
				$line = explode( ':', trim($line) );

				$key	= trim(array_shift( $line ));
				$value	= trim(join(':', $line ));
				$this->__set( $key, $value );
			}
		}
	}

	/**
	 * Set contentDuration. also implicitly set duration
	 *
	 * @param $timeCode Timecode output frm oggz-info
	 */
	private function setContentDuration( $timeCode ){
		$this->_contentDuration = $timeCode;
		$this->setDuration( $this->parseTimeCode( $timeCode ) );
	}

	/**
	 * Set duration. Casts to int!
	 */
	private function setDuration( $seconds ){
		$this->_duration = (int) $seconds;
	}

	/**
	 * Set framerate.
	 *
	 * Expects string output form oggz-info and parses it accordingly
	 */
	private function setVideoFramerate( $rate ){
		$rate = floatval(str_ireplace( 'fps', '', $rate ));
		$this->_videoFramerate = $rate;
	}

	/**
	 * Set audio samplerate
	 *
	 * Expects string output from oggz-info and parses accordingly
	 */
	private function setAudioSamplerate( $rate ){
		$rate = intval( str_ireplace( 'hz', '', $rate ));
		$this->_audioSamplerate = $rate;
	}

	/**
	 * parses timecoude output from oggz-info.
	 *
	 * @param string $timeCode String in an expected format: HH:MM:SS.MS
	 * @return int $seconds
	 */
	private function parseTimeCode( $timeCode ){
		list( $hour, $min, $sec ) = explode( ':', $timeCode );
		$duration = (intval($hour)*3600) + (intval($min)*60) + floatval($sec);
		return $duration;
	}

	/**
	 * Check for the existance of $name executable and returns the path
	 * or NULL
	 *
	 * @param $string $name Name of the executable
	 * @param return $path or null The path if found of the executable
	 */
	private function getPath( $name ){
		$search = self::OGGZ_SEARCH_PATH;

		// allow override from outside?
		if( defined( 'OGGZ_SEARCH_PATH' ) ){
			$search = OGGZ_SEARCH_PATH;
		}

		foreach( explode( ';', $search ) as $path ){
			$path = sprintf( '%s/%s', rtrim( $path, '/' ), $name );

			if( file_exists( $path ) && is_executable( $path ) ){
				return $path;
			}
		}
	}
}
